package com.roy.netty.sworddemo;

import java.net.InetSocketAddress;

import com.roy.netty.sworddemo.client.ClientSettings;
import com.roy.netty.sworddemo.client.MessageSender;
import com.roy.netty.sworddemo.client.NettyClientChannelInitializer;
import com.roy.netty.sworddemo.client.RandomServerLoadBalancer;
import com.roy.netty.sworddemo.client.ServerLoadBalancer;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class MyClient {

	private ClientSettings settings = new ClientSettings();
	
	public static void main(String[] args) throws Exception {
		//由于需要维护一个request-response的映射，所有一般需要设计一个ID字段用来进行对应。
		//这里就采取这样的格式，将中间的数字作为ID
		String message = "messageId:{"+System.currentTimeMillis()+"} test data";
		
		MyClient client = new MyClient();
		String response = client.sendMessage(message);
		System.out.println("received response: "+response);
	}

	public String sendMessage(String message) throws Exception {
		String res = "";
		// Configure the client.
		settings.setTransportServers("127.0.0.1:8089");
		
		NettyClientChannelInitializer channelInitializer = new NettyClientChannelInitializer(settings);
		
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
             .channel(NioSocketChannel.class)
             .option(ChannelOption.TCP_NODELAY, true)
             .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, settings.getTransportConnectTimeoutMillis())
				.option(ChannelOption.SO_REUSEADDR, settings.isTransportSoReuseAddress())
				.option(ChannelOption.TCP_NODELAY, settings.isTransportTcpNoDelay())
				.option(ChannelOption.SO_KEEPALIVE, settings.isTransportSoKeepAlive())
				.option(ChannelOption.SO_SNDBUF, settings.getTransportSoSendBufferSize())
				.option(ChannelOption.SO_RCVBUF, settings.getTransportSoReceiveBufferSize())
				.option(ChannelOption.SO_REUSEADDR, settings.isTransportSoReuseAddress())
             .handler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                	 channelInitializer.initChannel(ch);
                 }
             });

            ServerLoadBalancer serverLoadBalancer = new RandomServerLoadBalancer(settings.getTransportServers());
            InetSocketAddress address = serverLoadBalancer.getAddress();
            // Start the client.
            ChannelFuture channelFuture = b.connect(address).sync();
            if(channelFuture.isSuccess()) {
            	try {
            		Channel channel = channelFuture.channel();
            		MessageSender sender = (MessageSender) channel.pipeline().get("clientHandler");
            		res = sender.sendMessage(message, settings.getTransportFetchWaitMilliSeconds());
            	}finally {
            		channelFuture.channel().close().sync();
            	}
            }
        } finally {
            // Shut down the event loop to terminate all threads.
            group.shutdownGracefully();
        }
        return res;
	}
}
